#ifndef VL_COMMON_HPP
#define VL_COMMON_HPP

#include <cstddef>

namespace vl
{

typedef unsigned char byte;

template<class T>
T const& min(T const& a, T const& b)
{
	return a < b ? a : b;
}

template<class T>
T const& max(T const& a, T const& b)
{
	return a > b ? a : b;
}

template<class T>
void swap(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}

template<class T, class Derived, class ReturnT>
struct construct_proxy
{
	construct_proxy(void* p_)
	: p(p_)
	{
	}

	template<class T1>
	ReturnT operator()(T1 const& p1)
	{
		return self().constructed(*(new (p) T(p1)));
	}

	template<class T1, class T2>
	ReturnT operator()(T1 const& p1, T2 const& p2)
	{
		return self().constructed(*(new (p) T(p1, p2)));
	}

	template<class T1, class T2, class T3>
	ReturnT operator()(T1 const& p1, T2 const& p2, T3 const& p3)
	{
		return self().constructed(*(new (p) T(p1, p2, p3)));
	}
	
	template<class T1, class T2, class T3, class T4>
	ReturnT operator()(T1 const& p1, T2 const& p2, T3 const& p3, T4 const& p4)
	{
		return self().constructed(*(new (p) T(p1, p2, p3, p4)));
	}
	
	template<class T1, class T2, class T3, class T4, class T5>
	ReturnT operator()(T1 const& p1, T2 const& p2, T3 const& p3, T4 const& p4, T5 const& p5)
	{
		return self().constructed(*(new (p) T(p1, p2, p3, p4, p5)));
	}

	Derived& self()
	{
		return *static_cast<Derived *>(this);
	}

private:
	void* p;
};

template<class T>
struct simple_construct : public construct_proxy<T, simple_construct<T>, T& >
{
	//typedef T& return_type;

	simple_construct(void* p)
	: construct_proxy<T, simple_construct<T>, T& >(p)
	{
	}

	T& constructed(T& v)
	{
		return v;
	}

};

inline size_t hash_string(char const* s, size_t l)
{
	size_t h = 0;

	for(; l > sizeof(size_t); l -= sizeof(size_t))
	{
		h ^= *reinterpret_cast<size_t const*>(s);
		s += sizeof(size_t);		
	}

	for(; l > 0; --l)
	{
		h = (h ^ *s) + 1;
		++s;
	}

	return h;
}

template<class T>
struct auto_pimpl
{
public:
	auto_pimpl(auto_pimpl& b)
	: pimpl(b.pimpl)
	{
		b.pimpl = 0;
	}

	auto_pimpl& operator=(auto_pimpl& b)
	{
		pimpl = b.pimpl;
		b.pimpl = 0;
		return *this;
	}

	T* release()
	{
		T* p = pimpl;
		pimpl = 0;
		return p;
	}

protected:
	auto_pimpl(T* p)
	: pimpl(p)
	{
	}

	T* pimpl;
};

template<class T>
struct pimpl
{
protected:
	pimpl(T* p)
	: pimpl_(p)
	{
	}

	T* pimpl_;

private:
	pimpl(pimpl const& b);

	pimpl& operator=(pimpl const& b);
};

//#define FOREACH(t_, v_, c_) for(t_::iterator v_ = c_.begin(); v_ != c_.end(); ++v_)

template<class T>
struct local_set
{
	local_set(T& p, T n)
	: p(p), old(p)
	{
		p = n;
	}
	
	~local_set()
	{
		p = old;
	}
	
	T& p;
	T const old;
};

#define PP_CAT_I(a, b) a ## b
#define PP_CAT(a, b) PP_CAT_I(a, b)

#define VL_LOCAL_SET(type, var, value) vl::local_set<type> PP_CAT(_loc, __LINE__)(var, value)

int integer_be(byte const* p, int bytes);

#define VL_ENABLE_VISITOR(name) \
virtual void visit(name& visitor) { visitor.accept(*this); }
}

#endif // VL_COMMON_HPP
